home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1999 #2 / Amiga Plus CD - 1999 - No. 2.iso / System-Boost / Workbench / ToolManager / Source / Library / base.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  10KB  |  377 lines

  1. /*
  2.  * base.c  V3.1
  3.  *
  4.  * ToolManager Objects base class
  5.  *
  6.  * Copyright (C) 1990-98 Stefan Becker
  7.  *
  8.  * This source code is for educational purposes only. You may study it
  9.  * and copy ideas or algorithms from it for your own projects. It is
  10.  * not allowed to use any of the source codes (in full or in parts)
  11.  * in other programs. Especially it is not allowed to create variants
  12.  * of ToolManager or ToolManager-like programs from this source code.
  13.  *
  14.  */
  15.  
  16. #include "toolmanager.h"
  17.  
  18. /* Base class instance data */
  19. struct BaseClassData {
  20.  struct TMHandle *bcd_Handle;
  21.  ULONG            bcd_Flags;
  22.  const char      *bcd_Name;
  23.  ULONG            bcd_ID;
  24.  struct MinList   bcd_MemberList;
  25. };
  26. #define TYPED_INST_DATA(cl, o) ((struct BaseClassData *) INST_DATA((cl), (o)))
  27.  
  28. /* Flags for strings allocated in IFF parsing */
  29. #define IFFF_NAME 0x1  /* Object name */
  30.  
  31. /* Send TMM_Notify method to attached objects */
  32. #define DEBUGFUNCTION NotifyAttached
  33. static void NotifyAttached(struct BaseClassData *bcd)
  34. {
  35.  struct TMMemberData *tmmd1;
  36.  struct TMMemberData *tmmd2 = (struct TMMemberData *)
  37.                                GetTail(&bcd->bcd_MemberList);
  38.  
  39.  /* Notify attached objects that this object has changed               */
  40.  /* NOTE: We have to scan the list backwards, because the notification */
  41.  /*       might result in calls to the TMM_Attach/Detach methods which */
  42.  /*       makes the current node invalid!                              */
  43.  while (tmmd1 = tmmd2) {
  44.  
  45.   BASECLASS_LOG(LOG2(Notify, "Member 0x%08lx Data 0x%08lx",
  46.                      tmmd1->tmmd_Member, tmmd1))
  47.  
  48.   /* Previous attached object */
  49.   tmmd2 = (struct TMMemberData *) GetPred((struct MinNode *) tmmd1);
  50.  
  51.   /* Send notification */
  52.   DoMethod(tmmd1->tmmd_Member, TMM_Notify, tmmd1);
  53.  }
  54. }
  55.  
  56. /* Base class method: OM_NEW */
  57. #undef  DEBUGFUNCTION
  58. #define DEBUGFUNCTION BaseClassNew
  59. static ULONG BaseClassNew(Class *cl, Object *obj, struct opSet *ops)
  60. {
  61.  BASECLASS_LOG((LOG1(Tags, "0x%08lx", ops->ops_AttrList),
  62.                 PrintTagList(ops->ops_AttrList)))
  63.  
  64.  /* Call SuperClass */
  65.  if (obj = (Object *) DoSuperMethodA(cl, obj, (Msg) ops)) {
  66.   struct BaseClassData *bcd = TYPED_INST_DATA(cl, obj);
  67.  
  68.   /* Initialize instance data */
  69.   bcd->bcd_Handle = (struct TMHandle *) GetTagData(TMA_TMHandle, NULL,
  70.                                                     ops->ops_AttrList);
  71.   bcd->bcd_Flags  = 0;
  72.   bcd->bcd_Name   = "";
  73.   bcd->bcd_ID     = ++bcd->bcd_Handle->tmh_IDCounter;
  74.  
  75.   /* Initialize member list */
  76.   NewList((struct List *) &bcd->bcd_MemberList);
  77.  
  78.   /* Add new object to TM handle */
  79.   DoSuperMethod(cl, obj, OM_ADDTAIL, &bcd->bcd_Handle
  80.                  ->tmh_ObjectLists[GetTagData(TMA_ObjectType, 0,
  81.                                                ops->ops_AttrList)]);
  82.  }
  83.  
  84.  return((ULONG) obj);
  85. }
  86.  
  87. /* Base class method: OM_DISPOSE */
  88. #undef  DEBUGFUNCTION
  89. #define DEBUGFUNCTION BaseClassDispose
  90. static ULONG BaseClassDispose(Class *cl, Object *obj, Msg msg)
  91. {
  92.  struct BaseClassData *bcd = TYPED_INST_DATA(cl, obj);
  93.  
  94.  BASECLASS_LOG(LOG0(Disposing))
  95.  
  96.  /* Notify all linked objects that this object will be disposed */
  97.  {
  98.   struct TMMemberData *tmmd;
  99.  
  100.   /* Scan member list */
  101.   while (tmmd = (struct TMMemberData *) GetHead(&bcd->bcd_MemberList)) {
  102.  
  103.    BASECLASS_LOG(LOG2(Releasing, "Member 0x%08lx Data 0x%08lx",
  104.                       tmmd->tmmd_Member, tmmd))
  105.  
  106.    /* Cancel membership (TMM_Detach will be send) */
  107.    DoMethod(tmmd->tmmd_Member, TMM_Release, tmmd);
  108.   }
  109.  }
  110.  
  111.  /* Remove object from TM Handle */
  112.  DoSuperMethod(cl, obj, OM_REMOVE);
  113.  
  114.  /* Free name */
  115.  if (bcd->bcd_Flags & IFFF_NAME) FreeVector(bcd->bcd_Name);
  116.  
  117.  /* Call SuperClass */
  118.  return(DoSuperMethodA(cl, obj, msg));
  119. }
  120.  
  121. /* Base class method: OM_SET */
  122. #undef  DEBUGFUNCTION
  123. #define DEBUGFUNCTION BaseClassSet
  124. static ULONG BaseClassSet(Class *cl, Object *obj, struct opSet *ops)
  125. {
  126.  struct TagItem *tstate = ops->ops_AttrList;
  127.  struct TagItem *ti;
  128.  
  129.  BASECLASS_LOG((LOG1(Tags, "0x%08lx", ops->ops_AttrList),
  130.                 PrintTagList(ops->ops_AttrList)))
  131.  
  132.  /* Scan tag list */
  133.  while (ti = NextTagItem(&tstate))
  134.  
  135.   /* Set name? */
  136.   if (ti->ti_Tag == TMA_ObjectName) {
  137.    struct BaseClassData *bcd = TYPED_INST_DATA(cl, obj);
  138.  
  139.    /* Set new name */
  140.    bcd->bcd_Name = (const char *) ti->ti_Data;
  141.  
  142.    /* Notify attached objects */
  143.    NotifyAttached(bcd);
  144.   }
  145.  
  146.  /* Call SuperClass */
  147.  return(DoSuperMethodA(cl, obj, (Msg) ops));
  148. }
  149.  
  150. /* Base class method: OM_GET */
  151. #undef  DEBUGFUNCTION
  152. #define DEBUGFUNCTION BaseClassGet
  153. static ULONG BaseClassGet(Class *cl, Object *obj, struct opGet *opg)
  154. {
  155.  BASECLASS_LOG(LOG2(Attribute, "0x%08lx (%s)", opg->opg_AttrID,
  156.                     GetTagName(opg->opg_AttrID)))
  157.  
  158.  /* Which attribute is requested? */
  159.  switch(opg->opg_AttrID) {
  160.   case TMA_TMHandle:
  161.    *opg->opg_Storage = (ULONG) TYPED_INST_DATA(cl, obj)->bcd_Handle;
  162.    break;
  163.  
  164.   case TMA_ObjectName:
  165.    *opg->opg_Storage = (ULONG) TYPED_INST_DATA(cl, obj)->bcd_Name;
  166.    break;
  167.  
  168.   case TMA_ObjectID:
  169.    *opg->opg_Storage = TYPED_INST_DATA(cl, obj)->bcd_ID;
  170.    break;
  171.  
  172.   default:
  173.    DoSuperMethodA(cl, obj, (Msg) opg);
  174.    break;
  175.  }
  176.  
  177.  BASECLASS_LOG(LOG1(Result, "0x%08lx", *opg->opg_Storage))
  178.  
  179.  /* Return 1 to indicate that the method is implemented */
  180.  return(1);
  181. }
  182.  
  183. /* Base class method: TMM_Attach */
  184. #undef  DEBUGFUNCTION
  185. #define DEBUGFUNCTION BaseClassAttach
  186. static ULONG BaseClassAttach(Class *cl, Object *obj, struct TMP_Attach *tmpa)
  187. {
  188.  struct TMMemberData *tmmd;
  189.  
  190.  BASECLASS_LOG(LOG2(Member, "0x%08lx (%ld)", tmpa->tmpa_Object,
  191.                     tmpa->tmpa_Size))
  192.  
  193.  /* Allocate member data */
  194.  if (tmmd = GetVector(tmpa->tmpa_Size)) {
  195.  
  196.   /* Initialize member data */
  197.   tmmd->tmmd_Object = obj;
  198.   tmmd->tmmd_Member = tmpa->tmpa_Object;
  199.  
  200.   /* Add member to list */
  201.   AddTail((struct List *) &TYPED_INST_DATA(cl, obj)->bcd_MemberList,
  202.           (struct Node *) tmmd);
  203.  }
  204.  
  205.  BASECLASS_LOG(LOG1(Result, "0x%08lx", tmmd))
  206.  
  207.  /* Return pointer to member data */
  208.  return((ULONG) tmmd);
  209. }
  210.  
  211. /* Base class method: TMM_Detach */
  212. #undef  DEBUGFUNCTION
  213. #define DEBUGFUNCTION BaseClassDetach
  214. static ULONG BaseClassDetach(Class *cl, Object *obj, struct TMP_Detach *tmpd)
  215. {
  216.  BASECLASS_LOG(LOG2(Arguments, "Data 0x%08lx Member 0x%08lx",
  217.                     tmpd->tmpd_MemberData, tmpd->tmpd_MemberData->tmmd_Member))
  218.  
  219.  /* Remove member from list */
  220.  Remove((struct Node *) tmpd->tmpd_MemberData);
  221.  
  222.  /* Free member data */
  223.  FreeVector(tmpd->tmpd_MemberData);
  224.  
  225.  /* Return 1 to indicate that the method is implemented */
  226.  return(1);
  227. }
  228.  
  229. /* Base class method: TMM_ParseIFF */
  230. #undef  DEBUGFUNCTION
  231. #define DEBUGFUNCTION BaseClassParseIFF
  232. static ULONG BaseClassParseIFF(Class *cl, Object *obj,
  233.                                struct TMP_ParseIFF *tmppi)
  234. {
  235.  struct ContextNode *cn;
  236.  BOOL                rc = FALSE;
  237.  
  238.  BASECLASS_LOG(LOG1(Handle, "0x%08lx", tmppi->tmppi_IFFHandle))
  239.  
  240.  /* Get current chunk */
  241.  if (cn = CurrentChunk(tmppi->tmppi_IFFHandle)) {
  242.  
  243.   BASECLASS_LOG(LOG3(Chunk, "ID 0x%08lx Type 0x%08lx Size %ld", cn->cn_ID,
  244.                      cn->cn_Type, cn->cn_Size))
  245.  
  246.   /* Initialize IFF parser */
  247.   if ((PropChunk(tmppi->tmppi_IFFHandle, cn->cn_Type, ID_NAME) == 0) &&
  248.       (PropChunk(tmppi->tmppi_IFFHandle, cn->cn_Type, ID_DATA) == 0) &&
  249.       (StopOnExit(tmppi->tmppi_IFFHandle, cn->cn_Type, ID_FORM) == 0) &&
  250.       (ParseIFF(tmppi->tmppi_IFFHandle, IFFPARSE_SCAN) == IFFERR_EOC)) {
  251.    char *name;
  252.  
  253.    BASECLASS_LOG(LOG0(FORM parsed OK))
  254.  
  255.    /* Check for mandatory NAME property */
  256.    if (name = DuplicateProperty(tmppi->tmppi_IFFHandle, cn->cn_Type,
  257.                                 ID_NAME)) {
  258.     struct StoredProperty *sp;
  259.  
  260.     BASECLASS_LOG(LOG2(Name, "%s (0x%08lx)", name, name))
  261.  
  262.     /* Check for mandatory DATA property */
  263.     if (sp = FindProp(tmppi->tmppi_IFFHandle, cn->cn_Type, ID_DATA)) {
  264.      struct BaseClassData     *bcd = TYPED_INST_DATA(cl, obj);
  265.      struct StandardDATAChunk *sdc = sp->sp_Data;
  266.  
  267.      BASECLASS_LOG(LOG1(ID, "0x%08lx", sdc->sdc_ID))
  268.  
  269.      /* Set instance data */
  270.      bcd->bcd_Flags = IFFF_NAME;
  271.      bcd->bcd_Name  = name;
  272.      bcd->bcd_ID    = sdc->sdc_ID;
  273.  
  274.      /* Configuration data parsed */
  275.      rc = TRUE;
  276.  
  277.     } else
  278.  
  279.      /* Mandatory DATA chunk missing */
  280.      FreeVector(name);
  281.    }
  282.   }
  283.  }
  284.  
  285.  BASECLASS_LOG(LOG1(Result, "%ld", rc))
  286.  
  287.  return(rc);
  288. }
  289.  
  290. /* Base class method: TMM_ParseTags */
  291. #undef  DEBUGFUNCTION
  292. #define DEBUGFUNCTION BaseClassParseTags
  293. static ULONG BaseClassParseTags(Class *cl, Object *obj)
  294. {
  295.  BASECLASS_LOG(LOG0(Object changed))
  296.  
  297.  /* Notify attached objects */
  298.  NotifyAttached(TYPED_INST_DATA(cl, obj));
  299.  
  300.  /* Return success */
  301.  return(TRUE);
  302. }
  303.  
  304. /* Base class dispatcher */
  305. #undef  DEBUGFUNCTION
  306. #define DEBUGFUNCTION BaseClassDispatcher
  307. static __geta4 ULONG BaseClassDispatcher(__A0 Class *cl, __A2 Object *obj,
  308.                                          __A1 Msg msg)
  309. {
  310.  ULONG rc;
  311.  
  312.  BASECLASS_LOG(LOG3(Arguments, "Class 0x%08lx Object 0x%08lx Msg 0x%08lx",
  313.                     cl, obj, msg))
  314.  
  315.  switch(msg->MethodID) {
  316.   /* BOOPSI methods */
  317.   case OM_NEW:
  318.    rc = BaseClassNew(cl, obj, (struct opSet *) msg);
  319.    break;
  320.  
  321.   case OM_DISPOSE:
  322.    rc = BaseClassDispose(cl, obj, msg);
  323.    break;
  324.  
  325.   case OM_SET:
  326.    rc = BaseClassSet(cl, obj, (struct opSet *) msg);
  327.    break;
  328.  
  329.   case OM_GET:
  330.    rc = BaseClassGet(cl, obj, (struct opGet *) msg);
  331.    break;
  332.  
  333.   /* TM methods */
  334.   case TMM_Attach:
  335.    rc = BaseClassAttach(cl, obj, (struct TMP_Attach *) msg);
  336.    break;
  337.  
  338.   case TMM_Detach:
  339.    rc = BaseClassDetach(cl, obj, (struct TMP_Detach *) msg);
  340.    break;
  341.  
  342.   case TMM_ParseIFF:
  343.    rc = BaseClassParseIFF(cl, obj, (struct TMP_ParseIFF *) msg);
  344.    break;
  345.  
  346.   case TMM_ParseTags:
  347.    rc = BaseClassParseTags(cl, obj);
  348.    break;
  349.  
  350.   /* Unknown method -> delegate to SuperClass */
  351.   default:
  352.    rc = DoSuperMethodA(cl, obj, msg);
  353.    break;
  354.  }
  355.  
  356.  return(rc);
  357. }
  358.  
  359. /* Create base class */
  360. #undef  DEBUGFUNCTION
  361. #define DEBUGFUNCTION CreateBaseClass
  362. const Class *CreateBaseClass(void)
  363. {
  364.  Class *cl;
  365.  
  366.  /* Create class */
  367.  if (cl = MakeClass(NULL, ROOTCLASS, NULL, sizeof(struct BaseClassData), 0))
  368.  
  369.   /* Set dispatcher */
  370.   cl->cl_Dispatcher.h_Entry = (ULONG (*)()) BaseClassDispatcher;
  371.  
  372.  BASECLASS_LOG(LOG1(Class, "0x%08lx", cl))
  373.  
  374.  /* Return pointer to class */
  375.  return(cl);
  376. }
  377.